use std::sync::Arc;

use axum::{extract::State, routing::post, Json, Router};
use hostname as hostname_crate;
use machine_uid;
use serde::Deserialize;
use serde_json::{json, Value};
use tracing::info;

use crate::{manager::ManagerLock, response::Res};

//判断主锁是否存在
pub async fn has_mainlock(State(manager): State<Arc<ManagerLock>>) -> Res<bool> {
    let f = manager.has_mainlock();
    if f > 0 {
        return Res::success(true);
    }
    return Res::success(false);
}

#[derive(Deserialize)]
pub struct GetActivePsd {
    password: String,
    #[serde(rename = "serial")]
    serial: u32,
    #[serde(rename = "targetSerial")]
    target_serial: u32,
    #[serde(rename = "ulLimit")]
    ul_limit: u32,
}

//判断主锁是否存在
pub async fn get_active_psd(
    State(manager): State<Arc<ManagerLock>>,
    Json(GetActivePsd {
        password,
        serial,
        target_serial,
        ul_limit,
    }): Json<GetActivePsd>,
) -> Res<String> {
    let f = manager.has_mainlock();
    if f > 0 {
        info!("主锁:{}", f);
        let psd = manager.get_active_psd(&password, f, target_serial, ul_limit);
        if psd.status == 200 {
            return Res::success(psd.data.unwrap());
        }
    }
    Res::error("主锁不存在".to_string())
}

#[derive(Deserialize)]
pub struct ReadParams {
    serial: u32,
}

pub async fn read(
    State(manager): State<Arc<ManagerLock>>,
    Json(ReadParams { serial }): Json<ReadParams>,
) -> Res<Value> {
    let info = manager.get_info(serial);
    if info.is_some() {
        return Res::success(transform_info(info.unwrap()));
    }
    Res::error("信息不存在".to_string())
}

pub async fn get_sn(State(manager): State<Arc<ManagerLock>>) -> Res<Vec<u32>> {
    let sns = manager.get_sns().unwrap();
    Res::success(sns)
}

pub async fn get_info_all(State(manager): State<Arc<ManagerLock>>) -> Res<Vec<Value>> {
    let infos = manager.get_info_all();
    let infos = infos.iter().map(|v| transform_info(v.clone())).collect();
    Res::success(infos)
}
pub async fn test(State(manager): State<Arc<ManagerLock>>) -> Res<String> {
    Res::success("test".to_string())
}

#[derive(Deserialize)]
pub struct ReadParamsIDs {
    ids: Vec<u32>,
}
pub async fn read_data_byids(
    State(manager): State<Arc<ManagerLock>>,
    Json(ReadParamsIDs { ids }): Json<ReadParamsIDs>,
) -> Res<Vec<Value>> {
    let mut infos = manager.get_info_all();
    infos = infos
        .iter()
        .filter(|v| ids.contains(&(v["sn"].as_u64().unwrap() as u32)))
        .cloned()
        .collect();
    let infos = infos.iter().map(|v| transform_info(v.clone())).collect();
    Res::success(infos)
}

pub async fn get_machine_id(State(manager): State<Arc<ManagerLock>>) -> Res<String> {
    // 获取机器码
    let machine_id = machine_uid::get().unwrap_or_else(|_| "unknown".to_string());
    Res::success(machine_id)
}

pub async fn hostname(State(manager): State<Arc<ManagerLock>>) -> Res<String> {
    // 获取 hostname
    let hostname = hostname_crate::get()
        .map(|h| h.to_string_lossy().into_owned())
        .unwrap_or_else(|_| "unknown".to_string());

    Res::success(hostname)
}

pub async fn show(State(manager): State<Arc<ManagerLock>>) -> Res<String> {
    let _ = manager.sender.send(("show".to_string(), json!(true))).await;
    Res::success("show".to_string())
}
fn transform_info(mut data: Value) -> Value {
    if data["info"].get("loss").is_some() {
        data["status"] = json!(2);
        return data;
    }
    if data["info"].get("main").is_none() {
        data["status"] = json!(98);
        return data;
    }
    data["status"] = json!(1);
    data
}
pub fn router() -> Router<Arc<ManagerLock>> {
    Router::new()
        .route("/getActivePsd", post(get_active_psd))
        .route("/hasMainlock", post(has_mainlock))
        .route("/getSn", post(get_sn).get(get_sn))
        .route("/read", post(read))
        .route("/readAll", post(get_info_all))
        .route("/readDataByids", post(read_data_byids))
        .route("/getMachineId", post(get_machine_id))
        .route("/test", post(test))
        .route("/hostname", post(hostname))
        .route("/show", post(show))
}
